using LitJson;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System.Runtime.InteropServices;

namespace TCC.Framework
{
    /// <summary>
    /// 扩展函数类
    /// </summary>
    public static class FunctionExtension
    {
        /// <summary>
        /// 根据Key获取Value
        /// </summary>
        /// <typeparam name="Tkey"></typeparam>
        /// <typeparam name="Tvalue"></typeparam>
        /// <param name="dict">获取值的字典</param>
        /// <param name="key">键值</param>
        /// <returns></returns>
        public static Tvalue TryGet<Tkey, Tvalue>(this Dictionary<Tkey, Tvalue> dict, Tkey key)
        {
            Tvalue value;
            dict.TryGetValue(key, out value);
            return value;
        }

        /// <summary>
        /// 设置游戏对象激活状态
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="game"></param>
        /// <param name="value"></param>
        public static GameObject SetActive<T>(this T game,bool value)where T: Component
        {
            game.gameObject.SetActive(value);
            return game.gameObject;
        }

        /// <summary>
        /// 给物体添加交互事件 点击 拖拽...
        /// </summary>
        /// <param name="obj">物体对象</param>
        /// <param name="ev">交互类型</param>
        /// <param name="action">事件</param>
        public static void AddTriggerListener<T>(this T obj, EventTriggerType ev, UnityAction<BaseEventData> action)where T:Component
        {
            EventTrigger trigger = obj.GetComponent<EventTrigger>() ?? obj.gameObject.AddComponent<EventTrigger>();

            trigger.triggers = trigger.triggers ?? new List<EventTrigger.Entry>();

            foreach (var item in trigger.triggers)
            {
                if (item.eventID == ev)
                {
                    item.callback.AddListener(action);
                    return;
                }
            }

            EventTrigger.Entry entry = new EventTrigger.Entry();

            entry.eventID = ev;
            entry.callback.AddListener(action);
            trigger.triggers.Add(entry);
        }

        /// <summary>
        /// 移除物体交互事件
        /// </summary>
        /// <param name="obj">物体对象</param>
        /// <param name="ev">交互类型</param>
        /// <param name="action">事件</param>
        public static void RemoveTriggerListener<T>(this T obj, EventTriggerType ev, UnityAction<BaseEventData> action)where T:Component
        {
            EventTrigger trigger = obj.GetComponent<EventTrigger>();
            if (trigger == null)
                return;

            if (trigger.triggers==null||trigger.triggers.Count == 0)
                return;
            foreach (var item in trigger.triggers)
            {
                if (item.eventID == ev)
                    item.callback.RemoveListener(action);
            }
        }

        /// <summary>
        /// 根据名字查找对应类型子游戏对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="game"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static T GetChildComponent<T>(this GameObject game,string n)where T: UnityEngine.Object
        {
            Transform t = game.transform.Find(n);
            return t != null ? t.GetComponent<T>() : null;
        }

        /// <summary>
        /// 根据名字查找对应类型子游戏对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="game"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static T GetChildComponent<T>(this Component game, string n) where T : UnityEngine.Object
        {
            Transform t = game.transform.Find(n);
            return t != null ? t.GetComponent<T>() : null;
        }

        public static GameObject GetChildGameObject(this GameObject game,string name)
        {
            return game.transform.Find(name).gameObject;
        }

        public static RectTransform GetRectTransform(this GameObject game) => game.GetComponent<RectTransform>();


        public static bool IsNull<T>(this T obj) where T : UnityEngine.Object => obj == null;

        #region 反射工具
        /// <summary>
        /// 获取一个类里面的字段的值
        /// </summary>
        /// <typeparam name="T">要获取字段的类型</typeparam>
        /// <param name="type">要获取字段的类</param>
        /// <param name="fieldName">字段名</param>
        /// <returns></returns>
        public static T GetFieldValue<T>(this System.Object type,string fieldName)where T:class
        {
            return type.GetType().GetField(fieldName).GetValue(type) as T;
        }

        /// <summary>
        /// 获取一个类里面的字段的值
        /// </summary>
        /// <typeparam name="T">要获取字段的类型</typeparam>
        /// <param name="type">要获取字段的类</param>
        /// <param name="fieldName">字段名</param>
        /// <param name="bindingFlags">筛选字段的条件</param>
        /// <returns></returns>
        public static T GetFieldValue<T>(this System.Object type, string fieldName, BindingFlags bindingFlags) where T : class
        {
            return type.GetType().GetField(fieldName,bindingFlags).GetValue(type) as T;
        }

        /// <summary>
        /// 通过字段名为类里面字段赋值
        /// </summary>
        /// <param name="type"></param>
        /// <param name="fieldName">字段名</param>
        /// <param name="value">值</param>
        public static void SetFieldValue(this System.Object type, string fieldName, object value)
        {
            type.GetType().GetField(fieldName).SetValue(type, value);
        }


        #endregion

        /// <summary>
        /// 复制一个引用类型变量的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="refence"></param>
        /// <returns></returns>
        public static T CopyReferenceValue<T>(this T refence) where T : class, new()
        {
            T newRefence = new T();
            foreach (var item in refence.GetType().GetFields())
                newRefence.SetFieldValue(item.Name, refence.GetFieldValue<object>(item.Name));
            return newRefence;
        }

        /// <summary>
        /// 替换列表元素的位置
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">列表</param>
        /// <param name="index1">需替换位置元素下标</param>
        /// <param name="index2">需替换位置元素下标</param>
        public static void Swap<T>(this List<T> list,int index1,int index2)
        {
            if (index1 >= list.Count || index2 >= list.Count || index1 < 0 || index2 < 0) return;
            T temp1 = list[index1];
            list[index1] = list[index2];
            list[index2] = temp1;
        }


        #region String转换
        /// <summary>
        /// Json字符串转object
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonStr"></param>
        /// <returns></returns>
        public static T JsonStrToObject<T>(this string jsonStr)
        {
            return JsonMapper.ToObject<T>(jsonStr);
        }

        /// <summary>
        /// 泛型转Json字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ObjectToJsonStr<T>(this T obj)
        {
            return Regex.Unescape(JsonMapper.ToJson(obj));
        }

        /// <summary>
        /// string转int
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static int ToInt(this string str)
        {
            int value;
            if (int.TryParse(str, out value))
                return value;
            else
                throw new UnityException($"字符串【{str}】不能转换为整数");
        }

        /// <summary>
        /// 获取字符串中的第一个整数 例：abcd123nnn56  返回123
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static int GetStrInt(this string str)
        {
            return Regex.Replace(str, @"[^0-9]+", "").ToInt();
        }
        #endregion

        public static T Clone<T>(this T  clone,Transform parent,bool isUI=false)where T:UnityEngine.Object
        {
            UnityEngine.Object obj;
            if (parent != null)
                obj = GameObject.Instantiate(clone, parent);
            else
                obj = GameObject.Instantiate(clone);
            if(isUI)
            {
                UIBehaviour[] uis = (obj as UIBehaviour).GetComponentsInChildren<UIBehaviour>(true);
                for (int i = 0; i < uis.Length; i++)
                    uis[i].ResetID();
            }
            return obj as T;
        }

        /// <summary>
        /// object转byte[]
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static byte[] Obj2Bytes(this object obj)
        {
            byte[] buff = new byte[Marshal.SizeOf(obj)];
            IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buff, 0);
            Marshal.StructureToPtr(obj, ptr, true);
            return buff;
        }

        /// <summary>
        /// texture2D转byte[] 忽略图片源是否可读写
        /// </summary>
        /// <param name="texture2D"></param>
        /// <returns></returns>
        public static byte[] Texture2DToBytes(this Texture2D texture2D)
        {
            RenderTexture renderTex = RenderTexture.GetTemporary(
                    texture2D.width,
                    texture2D.height,
                    0,
                    RenderTextureFormat.Default,
                    RenderTextureReadWrite.Linear);

            Graphics.Blit(texture2D, renderTex);

            RenderTexture.active = renderTex;
            Texture2D readableText = new Texture2D(texture2D.width, texture2D.height);
            readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
            readableText.Apply();
            byte[] bytes = readableText.EncodeToPNG();
            return bytes;
        }

        /// <summary>
        /// 屏幕坐标转UI坐标
        /// </summary>
        /// <param name="position"></param>
        /// <param name="reference"></param>
        /// <param name="canvasType"></param>
        /// <returns></returns>
        public static Vector2 ScreenToUGUIPosition(this Vector3 position, RectTransform reference = null,  CanvasType canvasType = CanvasType.Overlay)
        {
            Vector2 anchoredPos = Vector2.zero;
            if (position.z < 0)
            {
                anchoredPos.Set(-100000, -100000);
            }
            else
            {
                position.z = 0;
                switch (canvasType)
                {
                    case CanvasType.Overlay:
                        RectTransformUtility.ScreenPointToLocalPointInRectangle(reference != null ? reference : ResetHandler.Instance.UIMagr.OverlayTransform, position, null, out anchoredPos);
                        break;
                    case CanvasType.Camera:
                        RectTransformUtility.ScreenPointToLocalPointInRectangle(reference != null ? reference : ResetHandler.Instance.UIMagr.CameraTransfrom, position, ResetHandler.Instance.MainCamera, out anchoredPos);
                        break;
                    case CanvasType.World:
                        RectTransformUtility.ScreenPointToLocalPointInRectangle(reference, position, ResetHandler.Instance.MainCamera, out anchoredPos);
                        break;
                }
            }
            return anchoredPos;
        }
    }
}
